package core

import (
	"context"
	"devops-server/global"
	"devops-server/initalize"
	"fmt"
	"github.com/spf13/cobra"
	"go.uber.org/zap"
	"net/http"
	"os"
	"os/signal"
	"time"
)

type Server struct{}

func NewServerCommand() *cobra.Command {
	cmd := &cobra.Command{
		Use:  "server",
		Long: "The server command is used to start the server.",
		Run: func(cmd *cobra.Command, args []string) {
			s := Server{}
			// 加载配置所有的配置文件
			s.Init()
			s.RunServer()
		},
	}
	return cmd
}

func (s *Server) Init() {
	// 所有全局变量在最初就初始化了; 这样可以满足并发安全；如果考虑多副本可以使用once
	global.Viper = Viper()         // 初始化配置文件viper
	global.Log = Zap()             // 初始化日志
	zap.ReplaceGlobals(global.Log) // 替换zap的默认全局变量; 也可以不替换，使用zap.S()
	global.Db = initalize.Gorm()   // 初始化数据库
	initalize.Redis()              // 初始化redis

	if global.Db == nil {
		global.Log.Error("mysql连接失败，退出程序")
		os.Exit(127)
	} else {
		initalize.RegisterTables(global.Db) // 注册表
		initalize.MigrateData(global.Db)    // 迁移表
		// 前面的库和表已经初始化好了才可以
		//global.Cron = initalize.InitCron() // 初始化定时任务
		global.Db.DB()
	}
}

func (s *Server) RunServer() {
	addr := fmt.Sprintf("%s:%d", global.Config.System.Host, global.Config.System.Port)
	router := initalize.Routers()
	srv := http.Server{
		Addr:           addr,
		Handler:        router,
		ReadTimeout:    120 * time.Second,
		WriteTimeout:   120 * time.Second,
		MaxHeaderBytes: 1 << 20,
	}
	go func() {
		// 服务器连接
		if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
			global.Log.Error("listen", zap.Error(err))
		}
	}()

	// 等待终端信号以优雅的关闭服务（设置5秒超时时间）
	quit := make(chan os.Signal)
	signal.Notify(quit, os.Interrupt)
	<-quit
	global.Log.Info("Showdown Server ...")
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()
	if err := srv.Shutdown(ctx); err != nil {
		global.Log.Error("Server Shutdown", zap.Error(err))
	}
	global.Log.Info("Server exiting")
}
